Skip to content

Comments

feat: upgrade to Zod v4#106

Draft
nsheaps wants to merge 4 commits intomainfrom
nate/dx-36--zod-upgrade-to-v4
Draft

feat: upgrade to Zod v4#106
nsheaps wants to merge 4 commits intomainfrom
nate/dx-36--zod-upgrade-to-v4

Conversation

@nsheaps
Copy link

@nsheaps nsheaps commented Jan 22, 2026

Summary

  • Upgrades stl-api monorepo to Zod v4.3.6 using the zod/v3 compatibility layer for backwards compatibility
  • Updates zod-openapi to v5.4.6 (official npm release, replacing Stainless fork)
  • Maintains full API compatibility for consumers by re-exporting from zod/v3

Changes

Package zod version Notes
stainless ^4.3.6 Core package with zod-openapi v5
prisma ^4.3.6 Module augmentation updated for zod/v3
ts-to-zod ^4.3.6 Simple upgrade
demo ^4.3.6 Updated from v3
client (unchanged) Uses zod-to-ts v1 (see note below)

Technical Notes

  • Uses zod/v3 compatibility layer throughout to avoid breaking changes
  • Module augmentations target "zod/v3" instead of "zod"
  • Type casts added where zod/v3 and zod-openapi v5 (native v4 types) interact

zod-to-ts v1 vs v2

zod-to-ts is kept at v1.2.0 because v2.0.0 has an ESM/CJS interop issue:

SyntaxError: Named export 'factory' not found. The requested module 'typescript' is a CommonJS module

Root cause: zod-to-ts v2 is ESM and does import { factory } from 'typescript'. The typescript package is CJS-only, and Node.js ESM can't import named exports from CJS modules. This fails in vitest's ESM context.

Workaround: v1.2.0 is CJS and works fine. It's compatible with Zod v4 at runtime (types need as any cast).

Future: When zod-to-ts fixes this (by using import ts from 'typescript'; const { factory } = ts;), we can upgrade.

Test plan

  • All package tests pass locally (stainless: 130, client: 78, hono: 15, ts-to-zod: 61)
  • Build succeeds across all packages
  • CI passes

🤖 Generated with Claude Code

Upgrades stl-api to Zod v4 while maintaining backwards compatibility through
the zod/v3 compatibility layer. This approach avoids breaking changes for
consumers while enabling access to Zod v4 features.

Changes:
- Upgrade zod to ^4.0.0 in stainless, prisma, and ts-to-zod packages
- Upgrade zod-openapi to ^5.4.6 (from stainless fork)
- Use zod/v3 re-exports throughout for backwards compatibility
- Update module augmentations to target "zod/v3"
- Add type casts where zod/v3 and zod/v4 types interact
- Regenerate client test types

Note: zod-to-ts remains at v1 due to ESM/CJS interop issues with v2.

Co-Authored-By: Claude Code (User Settings, in: ${CLAUDE_PROJECT_DIR}) <noreply@anthropic.com>
@nsheaps nsheaps self-assigned this Jan 22, 2026
- Update Zod from ^4.0.0 to ^4.3.6 in all packages
- Update Zod in demo package from v3 to v4
- Format generated-api-types.ts to fix prettier check

Co-Authored-By: Claude Code (User Settings, in: ${CLAUDE_PROJECT_DIR}) <noreply@anthropic.com>
@nsheaps nsheaps requested review from bkrausz and cjquines January 22, 2026 19:54
Copy link
Member

@cjquines cjquines left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if tests pass it's probably fine

nsheaps and others added 2 commits January 22, 2026 15:28
- Upgrade zod-to-ts from v1 to v2.0.0
- Add vitest deps.inline config for ESM/CJS interop with typescript
- Create comprehensive zod/v3 to zod v4 schema wrapper for zod-to-ts v2:
  - Maps v3 _def.typeName to v4 _zod.def.type format
  - Handles nested schemas (arrays, objects, optionals, unions, etc.)
  - Maps native enums to regular enums for proper TypeScript generation
  - Skips ZodNever catchall to avoid invalid [x: string]: never types

Co-Authored-By: Claude Code (User Settings, in: ${CLAUDE_PROJECT_DIR}) <noreply@anthropic.com>
Co-Authored-By: Claude Code (User Settings, in: ${CLAUDE_PROJECT_DIR}) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants